#ifndef KERNEL_H
#define KERNEL_H

#include <Globals.h>
#include <Map.h>
#include <MemoryManagement.h>

/**
	@author James Molloy <james@jamesmolloy.co.uk>
*/
class Kernel
{

public:
  Kernel();

  ~Kernel();

  /**
    Boot the kernel
  **/
  void run();
  
  /**
    Given a stack base pointer, follow it, return the next stack base
    pointer and also return the instruction pointer it returned to.
  **/
  static Address backtrace(Address basePointer, Address &returnAddress);
  
  /**
    Given the current stack, follow 'n' backtraces and return the
    return address found there.
  **/
  static Address backtrace(int n);
  
  /**
    Print a full backtrace from the current location. (Or, if specified,
    up to n stack frames.
  **/
  void printBacktrace(Address basePointer=0, int n=15);
  
  /**
    Prints first n words from the stack
  **/
  void printStacktrace(u32int n=64);
  
  inline static void memset(void *p, u8int c, u32int l)
  {
    u8int *temp = (u8int *)p;
    for( ; l != 0; l--) *temp++ = c;
  }
  
  inline static u8int *memcpy(u8int *dest, const u8int *src, u32int count)
  {
    const u8int *sp = (const u8int *)src;
    u8int *dp = (u8int *)dest;
    for(; count != 0; count--) *dp++ = *sp++;
    return dest;
  }

  inline static int strcmp(const char *in1, const char *in2)
  {
      int i = 0;
      int failed = 0;
      while(in1[i] != '\0' && in2[i] != '\0')
      {
          if(in1[i] != in2[i])
          {
              failed = 1;
              break;
          }
          i++;
      }
      // why did the loop exit?
      if( (in1[i] == '\0' && in2[i] != '\0') || (in1[i] != '\0' && in2[i] == '\0') )
          failed = 1;
  
      return failed;
  }
  
  inline static void strcpy(char *dest, const char *src)
  {
    int i = 0;
    while(src[i] != '\0')
    {
      dest[i] = src[i];
      i++;
    }
    dest[i] = '\0';
  }
  
  inline static u32int strlen(char *str)
  {
    u32int a = 0;
    while (*str)
    {
      str++;
      a++;
    }
    return a;
  }
  
private:

  /**
    Relocate the starting address for placement new, taking into account
    the information given us by the bootloader.
  **/
  void relocatePlacementAddress();

};

#endif
